package fr.bugtracker.bean.security;

import java.util.Iterator;

import javax.faces.application.FacesMessage;
import javax.faces.application.NavigationHandler;
import javax.faces.application.ViewExpiredException;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerWrapper;
import javax.faces.context.FacesContext;
import javax.faces.event.ExceptionQueuedEvent;
import javax.faces.event.ExceptionQueuedEventContext;
import javax.persistence.OptimisticLockException;

import fr.bugtracker.commun.outils.UtilsJsf;

/**
 * Capture de l'évènement ViewExpiredException
 * @author l.parrot1
 */
public class DefaultExceptionHandler extends ExceptionHandlerWrapper {

	/**
	 *
	 */
	private ExceptionHandler wrapped;

	/**
	 * Constructeur de la classe <code>DefaultExceptionHandler</code>.
	 * @param wrapped {@link ExceptionHandler}
	 */
	public DefaultExceptionHandler(ExceptionHandler wrapped) {
		this.wrapped = wrapped;
	}

	@Override
	public ExceptionHandler getWrapped() {
		return this.wrapped;
	}

	@Override
	public void handle() {
		FacesContext facesContext = FacesContext.getCurrentInstance();
		Iterator<ExceptionQueuedEvent> eventIterator = getUnhandledExceptionQueuedEvents().iterator();
		if (eventIterator.hasNext()) {
			captureErreurTechnique(eventIterator, facesContext);
		}
	}

	/**
	 * Capture les erreurs de type TechniqueException
	 * @param eventIterator {@link Iterator}< {@link ExceptionQueuedEvent} >
	 * @param facesContext {@link FacesContext}
	 */
	private void captureErreurTechnique(Iterator<ExceptionQueuedEvent> eventIterator, FacesContext facesContext) {

		final Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator();
		while (i.hasNext()) {
			ExceptionQueuedEvent event = i.next();
			ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();

			// get the exception from context
			Throwable t = context.getException();

			final FacesContext fc = FacesContext.getCurrentInstance();
			if (!(t instanceof ViewExpiredException) && fc != null) {
				final NavigationHandler nav = fc.getApplication().getNavigationHandler();

				// here you do what ever you want with exception
				try {

					String navigation = controleTypeException(fc, t);
					if (navigation != null) {
						nav.handleNavigation(fc, null, navigation);
						fc.renderResponse();
					}

				} finally {
					// remove it from queue
					i.remove();
				}
			}
		}
		// parent hanle
		getWrapped().handle();
	}

	/**
	 * Controle le type d'exception et retourne la redirection
	 * @param pFacesContext {@link FacesContext}
	 * @param exception {@link Throwable} l'exception a controler
	 * @return {@link String}
	 */
	private String controleTypeException(FacesContext pFacesContext, Throwable exception) {
		while (exception.getCause() != null) {
			exception = exception.getCause();
		}
		if (exception instanceof org.eclipse.persistence.exceptions.OptimisticLockException || exception instanceof OptimisticLockException) {
			UtilsJsf.addMessage(FacesMessage.SEVERITY_ERROR, "technique.dao.concurrence_acces");
			return null;
		}
		UtilsJsf.gestionExceptionSysteme(exception);
		return null;
	}

}
